﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace SP2010
{
    public abstract class SearchStringSerializer
    {
        public SearchStringSerializer()
        { }

        public abstract string GetSearchString();
        public abstract void LoadFromQueryString(NameValueCollection queryString);
        public abstract void LoadFromQueryStringForText(NameValueCollection queryString);

        private void AppendAND(ref StringBuilder blder)
        {
            int l = blder.Length;
            if (blder.Length > 0)
            {
                blder.Append(" AND ");
            }
        }

        private void AppendOR(ref StringBuilder blder)
        {
            int l = blder.Length;
            if (blder.Length > 0)
            {
                blder.Append(" OR ");
            }
        }

        private string GenerateKeywordSearchTerm(string key, string value, bool appendWildcard)
        {
            if (appendWildcard && !value.EndsWith("*") && !key.EndsWith("key"))
            {
                return string.Format("{0}:\"{1}*\"", key, value.Replace('*', ' ').Trim());
            }
            else
            {
                return string.Format("{0}:\"{1}\"", key, value.Trim());
            }
        }

        protected void AddItemToQuery(ref StringBuilder blder, string key, DateTime? start, DateTime? end)
        {
            string value = string.Empty;

            if (null != start && start.HasValue && null != end && end.HasValue)
            {
                string queryTerm = string.Format("{0}>={1} AND {0}<={2}", key, start.Value.ToString("MM/dd/yyyy"), end.Value.Date.ToString("MM/dd/yyyy"));
                AppendAND(ref blder);  
                blder.AppendFormat("({0})", queryTerm);
            }
            else
            {
                if (null != start && start.HasValue)
                {
                    string queryTerm = string.Format("{0}>={1}", key, start.Value.ToString("MM/dd/yyyy"));
                    AppendAND(ref blder);  
                    blder.AppendFormat("({0})", queryTerm);
                }

                if (null != end && end.HasValue)
                {
                    string queryTerm = string.Format("{0}<={1}", key, end.Value.ToString("MM/dd/yyyy"));
                    AppendAND(ref blder);  
                    blder.AppendFormat("({0})", queryTerm);
                }
            }
        }
        
        protected void AddItemToQuery(ref StringBuilder blder, string key, string value, bool appendWildcard = true)
        {
            if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
            {
                AppendAND(ref blder);                
                string queryTerm = GenerateKeywordSearchTerm(key, value, appendWildcard);
                blder.AppendFormat("({0})", queryTerm);
            }
        }

        protected void AddItemToQuery(ref StringBuilder blder, string key1, string key2, string value)
        {
            if (!string.IsNullOrEmpty(key1) && !string.IsNullOrEmpty(key1) && !string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
            {                
                AppendAND(ref blder);
                string queryTerm1 = GenerateKeywordSearchTerm(key1, value, true);
                string queryTerm2 = GenerateKeywordSearchTerm(key2, value, true);
                blder.AppendFormat("({0} OR {1})", queryTerm1, queryTerm2);
            }
        }

        protected void AddItemToQuery(ref StringBuilder blder, string key1, string value1, string key2, List<string> values2)
        {
            string queryTerm1 = string.Empty;
            
            if (!string.IsNullOrEmpty(key1) && !string.IsNullOrEmpty(key1) && !string.IsNullOrEmpty(value1) && !string.IsNullOrEmpty(value1.Trim()))
            {
               queryTerm1 = GenerateKeywordSearchTerm(key1, value1, false);
            }
                
            string queryTerm2 = string.Empty;

                if (!string.IsNullOrEmpty(key2) && null != values2 && values2.Count > 0)
                {
                    StringBuilder subQuery = new StringBuilder();
                    foreach (string value in values2)
                    {
                        if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
                        {
                            string currQuery = GenerateKeywordSearchTerm(key2, value, false);
                            subQuery.AppendFormat("{0} OR ", currQuery);
                        }
                    }

                    // Remove the last OR
                    if (subQuery.Length > 0)
                    {
                        queryTerm2 = subQuery.ToString().Substring(0, subQuery.Length - 4);                       
                    }
                }

                if (queryTerm2.Trim().Length > 0)
                {
                    AppendAND(ref blder);
                    blder.AppendFormat("({0} OR {1})", queryTerm1, queryTerm2);
                }                
            
        }

        protected void AddItemToQuery(ref StringBuilder blder, string key1, string key2, string key3, string value)
        {
            if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
            {
                AppendAND(ref blder);
                string queryTerm1 = GenerateKeywordSearchTerm(key1, value, true);
                string queryTerm2 = GenerateKeywordSearchTerm(key2, value, true);
                string queryTerm3 = GenerateKeywordSearchTerm(key3, value, true);
                blder.AppendFormat("({0} OR {1} OR {2})", queryTerm1, queryTerm2,queryTerm3);
            }
        }

        protected void AddItemToQuery(ref StringBuilder blder, List<string> keys, string value, bool appendWildcard = true)
        {
            if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
            {
                AppendAND(ref blder);

                List<string> searchTerm = new List<string>();
                keys.ForEach(i => searchTerm.Add(GenerateKeywordSearchTerm(i, value, appendWildcard)));
                blder.Append("(");
                blder.Append(searchTerm.Aggregate((i, j) => i + " OR " + j));
                blder.Append(")");
            }
        }

        protected void AddItemToQuery(ref StringBuilder blder, string key, bool? value)
        {
            string bValue = value.ToString();
            if (!string.IsNullOrEmpty(key) && value.HasValue)
            {
                string queryTerm = GenerateKeywordSearchTerm(key, bValue, false);
                AppendAND(ref blder);
                blder.AppendFormat("({0})", queryTerm);
            }
        }

        protected void AddItemToQuery(ref StringBuilder blder, string key, List<string> values)
        {
            if (!string.IsNullOrEmpty(key))
            {
                StringBuilder subQuery = new StringBuilder();
                foreach (string value in values)
                {
                    if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
                    {
                        string currQuery = GenerateKeywordSearchTerm(key, value, false);
                        subQuery.AppendFormat("{0} OR ", currQuery);
                    }
                }

                // Remove the last OR
                if (subQuery.Length > 0)
                {
                    string queryTerm = subQuery.ToString().Substring(0, subQuery.Length-4);

                    if (queryTerm.Trim().Length > 0)
                    {
                        AppendAND(ref blder);                       
                        blder.AppendFormat("({0})", queryTerm);
                    }
                }
            }
        }
        
        protected void AddItemToQuery(ref StringBuilder blder, string key, List<string> values, string key2, List<string> values2)
        {
            if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(key2))
            {
                StringBuilder subQuery = new StringBuilder();
                foreach (string value in values)
                {
                    if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(value.Trim()))
                    {
                        string currQuery = GenerateKeywordSearchTerm(key, value, false);
                        subQuery.AppendFormat("{0} OR ", currQuery);
                    }
                }

                StringBuilder subQuery2 = new StringBuilder();
                foreach (string value2 in values2)
                {
                    if (!string.IsNullOrEmpty(value2) && !string.IsNullOrEmpty(value2.Trim()))
                    {
                        string currQuery2 = GenerateKeywordSearchTerm(key2, value2, false);
                        subQuery2.AppendFormat("{0} OR ", currQuery2);
                    }
                }

                if ((subQuery.Length > 0) && (subQuery2.Length > 0))
                {
                    string queryTerm = subQuery.ToString().Substring(0, subQuery.Length - (" OR ").Length);
                    string queryTerm2 = subQuery2.ToString().Substring(0, subQuery2.Length - (" OR ").Length);

                    if ((queryTerm.Trim().Length > 0) && (queryTerm2.Trim().Length > 0))
                    {
                        AppendAND(ref blder);
                        blder.AppendFormat("({0} OR {1})", queryTerm, queryTerm2);
                    }
                }
                else
                {
                    if (subQuery.Length > 0)
                    {
                        string queryTerm = subQuery.ToString().Substring(0, subQuery.Length - (" OR ").Length);
                        
                        if (queryTerm.Trim().Length > 0)
                        {
                            AppendAND(ref blder); 
                            blder.AppendFormat("({0})", queryTerm);
                        }
                    }

                    if (subQuery2.Length > 0)
                    {
                        string queryTerm2 = subQuery2.ToString().Substring(0, subQuery2.Length - (" OR ").Length);

                        if (queryTerm2.Trim().Length > 0)
                        {
                            AppendAND(ref blder); 
                            blder.AppendFormat("({0})", queryTerm2);
                        }
                    }
                }
            }
        }

        public IList<string> GetProperties(string data, string queryParam)
        {
            string pattern = @"(?<Property>[^\s\(]+)[:](?<Value>[^\s\()]+)";

            var metadataColl = from Match m in Regex.Matches(data, pattern)
                               select new
                               {
                                   Property = m.Groups["Property"].Value,
                                   Value = m.Groups["Value"].Value
                               };

            List<string> paramsLoaded = new List<string>();
            foreach (var metadata in metadataColl)
            {
                paramsLoaded.Add(metadata.Property);
            }
           
            return paramsLoaded.Distinct().ToList();
        }
   
        public List<string> GetValue(string queryString, string key)
        {            
            List<string> valuesToReturn = new List<string>();

            queryString = queryString.ToUpper();

            if (queryString.Contains(key))
            {
                // Get the start location of the key 
                int startIndex = queryString.IndexOf(key);

                // Chop the string for the string before the key 
                string temp100 = queryString.Substring(startIndex, queryString.Length - startIndex - 1);
                string[] queryStringCollection = temp100.Split(new string[] { key }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string value in queryStringCollection)
                {
                    if (!string.IsNullOrEmpty(value))
                    {
                        if (value.IndexOf('\"') > 0)
                        {
                            string trimmedValue = value.Substring(value.IndexOf('\"') + 1);

                            if (!string.IsNullOrEmpty(trimmedValue) && trimmedValue.IndexOf('\"') > 0)
                            {
                                trimmedValue = trimmedValue.Substring(0, trimmedValue.IndexOf('\"'));
                                string cleanup = trimmedValue.Replace(":", " ").Replace("\"", " ").Replace("*", " ").Trim();
                                valuesToReturn.Add(cleanup);
                            }
                            else
                            {
                                valuesToReturn.Add(trimmedValue);
                            }
                        }
                        else
                        {
                            valuesToReturn.Add(value);
                        }
                    }
                    else
                    {
                        valuesToReturn.Add(value);
                    }
                }
            }

            return valuesToReturn;
        }

        public List<string> ParseQueryString(NameValueCollection queryStringColl, string key)
        {
            List<string> value = new List<string>();

            if (null != queryStringColl["k"])
            {
                string searchQuery = queryStringColl["k"];
                try
                {
                    return GetValue(searchQuery, key.ToUpper());
                }
                catch (Exception)
                {
                    return value;
                }
            }
            else
            {
                return value;
            }
        }

        public List<string> ParseQueryStringForText(NameValueCollection queryStringColl, string key)
        {
            List<string> value = new List<string>();

            if (null != queryStringColl["WHSPARAM"])
            {
                string searchQuery = queryStringColl["WHSPARAM"];
                try
                {
                    return GetValue(searchQuery, key.ToUpper());
                }
                catch (Exception)
                {
                    return value;
                }
            }
            else
            {
                return value;
            }
        }
    }
}
